package br.unifor.sd.bolsa.servidor.impl;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import br.unifor.sd.bolsa.interfaces.MessageListener;
import br.unifor.sd.bolsa.interfaces.ServidorInterface;
import br.unifor.sd.bolsa.util.Colecao;
import br.unifor.sd.bolsa.util.Dialeto;
import java.net.InetAddress;
import java.util.Iterator;

/**
 *
 * @author andrea
 */
public class ServidorImplUDP implements ServidorInterface {

    /**
     * Implementação de listener para notificar tela ao chegar uma nova mensagem.
     */
    private List<MessageListener> listeners;
    /**
     * Objeto socket lado servidor.
     */
    private DatagramSocket socket;
    /**
     * Flag para indicar que o servidor deve continuar ligado.
     */
    private boolean ligado;

    private Colecao colecao;

    private List <Cliente> clientes;

    private DatagramPacket pacote;

    @SuppressWarnings("empty-statement")
    public ServidorImplUDP() throws IOException {
        ligado = Boolean.TRUE;
        listeners = new ArrayList<MessageListener>();
        colecao = new Colecao();
        colecao.popularRandomico();
        clientes = new ArrayList<Cliente>();
    }

    /**
     * Implementação do iniciar servidor em TCP
     * @param porta Porta a ser utilizada.
     * @throws java.io.IOException
     */
    public void iniciar(int porta) throws IOException {
        socket = new DatagramSocket(porta);
    }

    /**
     * Ação de stop no servidor.
     * @throws java.io.IOException
     */
    public void parar() throws IOException {
        socket.close();
        ligado = Boolean.FALSE;
    }

    public void escutar() {
		try {
			String oQueChegou = "";
			String oQueSaiu = "";
			byte[] b = new byte[1024];
			while (ligado) {
				DatagramPacket pacote = new DatagramPacket(b, b.length);
				socket.receive(pacote);
				addCliente(pacote.getAddress(), pacote.getPort());
				oQueChegou = new String(pacote.getData(), 0, pacote.getLength());
				// TODO: Tratar chegar Comprar ou vender?
				message(System.getProperty("line.separator") + "Chegou isso: "
						+ System.getProperty("line.separator") + oQueChegou
						+ System.getProperty("line.separator"));
				tratarSaida(oQueChegou);
				// Sempre responder com lista Completa de ações.
				oQueSaiu = Dialeto.listaDeAcoesToString(colecao.getLista());
				message(System.getProperty("line.separator") + "O que saiu:"
						+ System.getProperty("line.separator") + oQueSaiu);
				notificarTodos(oQueSaiu);
			}
		} catch (IOException ex) {
			Logger.getLogger(ServidorImplUDP.class.getName()).log(Level.SEVERE,
					null, ex);
		}
	}


	private void notificarTodos(String oQueSaiu) {
		for (int i = 0; i < clientes.size(); i++) {
			try {
				pacote = new DatagramPacket(oQueSaiu.getBytes(), oQueSaiu.getBytes().length,
						clientes.get(i).getAddress(), clientes.get(i).getPorta());
				socket.send(pacote);
			} catch (IOException ex) {
				Logger.getLogger(ServidorImplUDP.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}

	private void tratarSaida(String oQueChegou) {
		String[] split = oQueChegou.split("#");
		String operacao = split[0];

		if (operacao.equals("comprar")) {
			int acaoId = Integer.parseInt(split[1]);
			String dono = split[2];
			colecao.mudarDono(acaoId, dono);
		} else if (operacao.equals("comprarValor")) {
			int acaoId = Integer.parseInt(split[1]);
			String dono = split[2];
			Double valor = Double.parseDouble(split[3]);
			colecao.mudarDonoValor(acaoId, dono, valor);
		} else if (operacao.equals("vender")) {

		} else {

		}
	}

    public void addListener(MessageListener listener){
        listeners.add(listener);
    }

    private void message(String msg)
    {
        for(int i=0;i<listeners.size();i++){
            listeners.get(i).onMessage(msg);
        }
    }

    private void addCliente(InetAddress address, int porta) {
		Cliente c = new Cliente(address, porta);
		boolean achou = false;
		for (Iterator iter = clientes.iterator(); iter.hasNext();) {
			Cliente element = (Cliente) iter.next();
			if (element.getAddress().equals(c.getAddress()) && element.getPorta() == c.getPorta()) {
				achou = true;
			}
		}
		if (!achou) {
			clientes.add(c);
		}
	}
}
